package me.zhenqu.redis.utils;


import java.util.Arrays;
import java.util.Vector;

/**
 * @author cyh
 */
public class ByteUtil {
    // 按照网络字节序，高位在前
    public static long toLong(byte[] bytes, int from, int length) {
        if (length == 0) {
            return 0;
        }
//        long result = 0;
        byte[] temp = new byte[length];
        int l = bytes.length - from;

        try {
            System.arraycopy(bytes, from, temp, 0, l > length ? length : l);
        } catch (Exception e) {
            System.out.println("l = " + l);
            System.out.println("length = " + length);
            System.out.println("temp.length = " + temp.length);
            System.out.println("bytes.length = " + bytes.length);
            System.out.println("from = " + from);
            e.printStackTrace();
            return 0;
        }
//        doSwap(temp);
/*
        for (int i = 0; i < length; i++) {
            result += ((bytes[i + from] & 0xff) << ((length - i - 1) * 8));
        }
*/

        return Long.parseLong(ByteUtil.toHexString(temp), 16);
    }


    public static int toInt(byte[] bytes, int from, int length) {
        return (int) toLong(bytes, from, length);
    }

    public static byte[] parseInt(int value, int length) {
        byte[] result = new byte[length];

        for (int i = 0; i < length; i++) {
            result[i] = (byte) ((value >> ((length - i - 1) * 8)) & 0xff);
//            mask = mask << 8;
        }

//        doSwap(result);
        return result;
    }

    public static byte[] parseLong(long value, int length) {
        byte[] result = new byte[length];

        for (int i = 0; i < length; i++) {
            result[i] = (byte) ((value >> ((length - i - 1) * 8)) & 0xff);
        }

        return result;
    }

/*
    private static void doSwap(byte[] result) {
        for (int i = 0; i < result.length / 2; i++) {
            byte b = result[i * 2];
            result[i * 2] = result[i * 2 + 1];
            result[i * 2 + 1] = b;
        }
    }
*/

    public static void println(byte[] bytes) {
        println(bytes, 0, bytes.length);
    }

    public static void println(byte[] bytes, int offset, int length) {
        for (int i = offset; i < offset + length; i++) {
            int b = bytes[i]; // & 0x0f;
/*
            if (b == -1) {
                b = 0xf;
            }
            if (b > 9) {
                System.out.print(Character.toString((char) ('A' + b - 10)));
            } else System.out.print(b);
*/
            if (b >= 0 && b < 0x10) {
                System.out.print(0);
            }
            System.out.print(Integer.toHexString(b & 0xff));
            /*if (i % 2 == 1) */
//            System.out.print(' ');
        }
        System.out.println();
    }

    public static byte[] getBytes(String str) {
/*
        byte[] bytes = str.getBytes();
        byte[] result = new byte[bytes.length * 2];
        for (int i = 0; i < bytes.length; i++) {
            result[i * 2] = (byte) ((bytes[i] & 0xf0) >> 4);
            result[i * 2 + 1] = (byte) (bytes[i] & 0x0f);
        }

        return result;
*/
        return str.getBytes();
    }

    public static String toString(byte[] bytes) {
        StringBuilder builder = new StringBuilder();
        for (byte b : bytes) {
            /*
            if (b == -1) {
                b = 0xf;
            }
            if (b > 9) {
                System.out.print(Character.toString((char) ('A' + b - 10)));
            } else System.out.print(b);
*/
            if (b >= 0 && b < 0x10) {
                builder.append(0);
            }
            builder.append(Integer.toHexString(b & 0xff));
            /*if (i % 2 == 1) */
//            builder.append(' ');
        }
        return builder.toString();
    }

    public static String toString(byte[] bytes, int offset, int size) {
        StringBuilder builder = new StringBuilder();
        for (int i = offset; i < bytes.length && i < size; i++) {
            byte b = bytes[i];
            /*
            if (b == -1) {
                b = 0xf;
            }
            if (b > 9) {
                System.out.print(Character.toString((char) ('A' + b - 10)));
            } else System.out.print(b);
*/
            if (b >= 0 && b < 0x10) {
                builder.append(0);
            }
            builder.append(Integer.toHexString(b & 0xff));
            /*if (i % 2 == 1) */
//            builder.append(' ');
        }
        return builder.toString();
    }

    public static byte[] parse(String hexString) {
        if (hexString.length() % 2 != 0) {
            hexString = "0" + hexString;
        }
        int len = hexString.length();
        byte[] result = new byte[len / 2];
        for (int i = 0; i < len; i++) {
            char c = hexString.charAt(i);
            int offset = i >> 1;
            int val = Character.digit(c, 16);
            if (val == -1) {
                throw new IllegalArgumentException("hex string format error - " + c);
            }
            if (i % 2 == 0) {
                result[offset] += (byte) (val << 4);
            } else {
                result[offset] += val;
            }
        }
        return result;
    }

    public static String toHexString(byte[] bytes) {
        StringBuilder builder = new StringBuilder();
        for (byte b : bytes) {
            if (b >= 0 && b < 0x10) {
                builder.append(0);
            }
            builder.append(Integer.toHexString(b & 0xff));
        }
        return builder.toString();
    }

    public static double toDouble(byte[] value, int offset, int length) {
//        byte[] temp = new byte[length];
//        System.arraycopy(value, offset, temp, 0, length);
//        swap(temp);
        return Double.longBitsToDouble(toLong(value, offset, length));
    }

    static void swap(byte[] temp) {
        int length = temp.length;
        for (int i = 0; i < length / 2; i++) {
            byte b = temp[i];
            temp[i] = temp[length - i - 1];
            temp[length - i - 1] = b;
        }
    }

    public static float toFloat(byte[] bytes, int from, int length) {
        byte[] temp = new byte[length];
        System.arraycopy(bytes, from, temp, 0, length);

        return Float.intBitsToFloat(toInt(temp, 0, length));
    }

    public static byte[] subarray(byte[] buffer, int offset, int size) {
        byte[] ret = new byte[size];
        try {
            System.arraycopy(buffer, offset, ret, 0, size);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ret;
    }

    private static final byte[] b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".getBytes();

    private static byte val(byte foo) {
        if (foo == '=') return 0;
        for (int j = 0; j < b64.length; j++) {
            if (foo == b64[j]) return (byte) j;
        }
        return 0;
    }

    public static byte[] fromBase64(byte[] buf, int start, int length) {
        byte[] foo = new byte[length];
        int j = 0;
        for (int i = start; i < start + length; i += 4) {
            foo[j] = (byte) ((val(buf[i]) << 2) | ((val(buf[i + 1]) & 0x30) >>> 4));
            if (buf[i + 2] == (byte) '=') {
                j++;
                break;
            }
            foo[j + 1] = (byte) (((val(buf[i + 1]) & 0x0f) << 4) | ((val(buf[i + 2]) & 0x3c) >>> 2));
            if (buf[i + 3] == (byte) '=') {
                j += 2;
                break;
            }
            foo[j + 2] = (byte) (((val(buf[i + 2]) & 0x03) << 6) | (val(buf[i + 3]) & 0x3f));
            j += 3;
        }
        byte[] bar = new byte[j];
        System.arraycopy(foo, 0, bar, 0, j);
        return bar;
    }

    static byte[] toBase64(byte[] buf, int start, int length) {

        byte[] tmp = new byte[length * 2];
        int i, j, k;

        int foo = (length / 3) * 3 + start;
        i = 0;
        for (j = start; j < foo; j += 3) {
            k = (buf[j] >>> 2) & 0x3f;
            tmp[i++] = b64[k];
            k = (buf[j] & 0x03) << 4 | (buf[j + 1] >>> 4) & 0x0f;
            tmp[i++] = b64[k];
            k = (buf[j + 1] & 0x0f) << 2 | (buf[j + 2] >>> 6) & 0x03;
            tmp[i++] = b64[k];
            k = buf[j + 2] & 0x3f;
            tmp[i++] = b64[k];
        }

        foo = (start + length) - foo;
        if (foo == 1) {
            k = (buf[j] >>> 2) & 0x3f;
            tmp[i++] = b64[k];
            k = ((buf[j] & 0x03) << 4) & 0x3f;
            tmp[i++] = b64[k];
            tmp[i++] = (byte) '=';
            tmp[i++] = (byte) '=';
        } else if (foo == 2) {
            k = (buf[j] >>> 2) & 0x3f;
            tmp[i++] = b64[k];
            k = (buf[j] & 0x03) << 4 | (buf[j + 1] >>> 4) & 0x0f;
            tmp[i++] = b64[k];
            k = ((buf[j + 1] & 0x0f) << 2) & 0x3f;
            tmp[i++] = b64[k];
            tmp[i++] = (byte) '=';
        }
        byte[] bar = new byte[i];
        System.arraycopy(tmp, 0, bar, 0, i);
        return bar;

//    return sun.misc.BASE64Encoder().encode(buf);
    }

    static String[] split(String foo, String split) {
        if (foo == null)
            return null;
        byte[] buf = foo.getBytes();
        Vector<String> bar = new Vector<String>();
        int start = 0;
        int index;
        while (true) {
            index = foo.indexOf(split, start);
            if (index >= 0) {
                bar.addElement(new String(buf, start, index - start));
                start = index + 1;
                continue;
            }
            bar.addElement(new String(buf, start, buf.length - start));
            break;
        }
        String[] result = new String[bar.size()];
        for (int i = 0; i < result.length; i++) {
            result[i] = bar.elementAt(i);
        }
        return result;
    }

    static boolean glob(byte[] pattern, byte[] name) {
        return glob0(pattern, 0, name, 0);
    }

    static private boolean glob0(byte[] pattern, int pattern_index,
                                 byte[] name, int name_index) {
        if (name.length > 0 && name[0] == '.') {
            if (pattern.length > 0 && pattern[0] == '.') {
                if (pattern.length == 2 && pattern[1] == '*') return true;
                return glob(pattern, pattern_index + 1, name, name_index + 1);
            }
            return false;
        }
        return glob(pattern, pattern_index, name, name_index);
    }

    static private boolean glob(byte[] pattern, int pattern_index,
                                byte[] name, int name_index) {
        //System.err.println("glob: "+new String(pattern)+", "+pattern_index+" "+new String(name)+", "+name_index);

        int patternlen = pattern.length;
        if (patternlen == 0)
            return false;

        int namelen = name.length;
        int i = pattern_index;
        int j = name_index;

        while (i < patternlen && j < namelen) {
            if (pattern[i] == '\\') {
                if (i + 1 == patternlen)
                    return false;
                i++;
                if (pattern[i] != name[j])
                    return false;
                i += skipUTF8Char(pattern[i]);
                j += skipUTF8Char(name[j]);
                continue;
            }

            if (pattern[i] == '*') {
                while (i < patternlen) {
                    if (pattern[i] == '*') {
                        i++;
                        continue;
                    }
                    break;
                }
                if (patternlen == i)
                    return true;

                byte foo = pattern[i];
                if (foo == '?') {
                    while (j < namelen) {
                        if (glob(pattern, i, name, j)) {
                            return true;
                        }
                        j += skipUTF8Char(name[j]);
                    }
                    return false;
                } else if (foo == '\\') {
                    if (i + 1 == patternlen)
                        return false;
                    i++;
                    foo = pattern[i];
                    while (j < namelen) {
                        if (foo == name[j]) {
                            if (glob(pattern, i + skipUTF8Char(foo),
                                    name, j + skipUTF8Char(name[j]))) {
                                return true;
                            }
                        }
                        j += skipUTF8Char(name[j]);
                    }
                    return false;
                }

                while (j < namelen) {
                    if (foo == name[j]) {
                        if (glob(pattern, i, name, j)) {
                            return true;
                        }
                    }
                    j += skipUTF8Char(name[j]);
                }
                return false;
            }

            if (pattern[i] == '?') {
                i++;
                j += skipUTF8Char(name[j]);
                continue;
            }

            if (pattern[i] != name[j])
                return false;

            i += skipUTF8Char(pattern[i]);
            j += skipUTF8Char(name[j]);

            if (!(j < namelen)) {         // name is end
                if (!(i < patternlen)) {    // pattern is end
                    return true;
                }
                if (pattern[i] == '*') {
                    break;
                }
            }
            continue;
        }

        if (i == patternlen && j == namelen)
            return true;

        if (!(j < namelen) &&  // name is end
                pattern[i] == '*') {
            boolean ok = true;
            while (i < patternlen) {
                if (pattern[i++] != '*') {
                    ok = false;
                    break;
                }
            }
            return ok;
        }

        return false;
    }

    static String quote(String path) {
        byte[] _path = str2byte(path);
        int count = 0;
        for (int i = 0; i < _path.length; i++) {
            byte b = _path[i];
            if (b == '\\' || b == '?' || b == '*')
                count++;
        }
        if (count == 0)
            return path;
        byte[] _path2 = new byte[_path.length + count];
        for (int i = 0, j = 0; i < _path.length; i++) {
            byte b = _path[i];
            if (b == '\\' || b == '?' || b == '*') {
                _path2[j++] = '\\';
            }
            _path2[j++] = b;
        }
        return byte2str(_path2);
    }

    static String unquote(String path) {
        byte[] foo = str2byte(path);
        byte[] bar = unquote(foo);
        if (foo.length == bar.length)
            return path;
        return byte2str(bar);
    }

    static byte[] unquote(byte[] path) {
        int pathlen = path.length;
        int i = 0;
        while (i < pathlen) {
            if (path[i] == '\\') {
                if (i + 1 == pathlen)
                    break;
                System.arraycopy(path, i + 1, path, i, path.length - (i + 1));
                pathlen--;
                i++;
                continue;
            }
            i++;
        }
        if (pathlen == path.length)
            return path;
        byte[] foo = new byte[pathlen];
        System.arraycopy(path, 0, foo, 0, pathlen);
        return foo;
    }
/*

    private static String[] chars = {
            "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"
    };
*/


    static boolean array_equals(byte[] foo, byte bar[]) {
        int i = foo.length;
        if (i != bar.length) return false;
        for (int j = 0; j < i; j++) { if (foo[j] != bar[j]) return false; }
        //try{while(true){i--; if(foo[i]!=bar[i])return false;}}catch(Exception e){}
        return true;
    }

    static byte[] str2byte(String str, String encoding) {
        if (str == null)
            return null;
        try { return str.getBytes(encoding); }
        catch (java.io.UnsupportedEncodingException e) {
            return str.getBytes();
        }
    }

    static byte[] str2byte(String str) {
        return str2byte(str, "UTF-8");
    }

    static String byte2str(byte[] str, String encoding) {
        try { return new String(str, encoding); }
        catch (java.io.UnsupportedEncodingException e) {
            return new String(str);
        }
    }

    static String byte2str(byte[] str) {
        return byte2str(str, "UTF-8");
    }

    /*
    static byte[] char2byte(char[] foo){
      int len=0;
      for(int i=0; i<foo.length; i++){
        if((foo[i]&0xff00)==0) len++;
        else len+=2;
      }
      byte[] bar=new byte[len];
      for(int i=0, j=0; i<foo.length; i++){
        if((foo[i]&0xff00)==0){
          bar[j++]=(byte)foo[i];
        }
        else{
          bar[j++]=(byte)(foo[i]>>>8);
          bar[j++]=(byte)foo[i];
        }
      }
      return bar;
    }
    */
    public static void bzero(byte[] foo) {
        if (foo == null)
            return;
        for (int i = 0; i < foo.length; i++)
            foo[i] = 0;
    }

    public static String diffString(String str, String[] not_available) {
        String[] stra = split(str, ",");
        String result = null;
        loop:
        for (int i = 0; i < stra.length; i++) {
            for (int j = 0; j < not_available.length; j++) {
                if (stra[i].equals(not_available[j])) {
                    continue loop;
                }
            }
            if (result == null) { result = stra[i]; } else { result = result + "," + stra[i]; }
        }
        return result;
    }

    private static int skipUTF8Char(byte b) {
        if ((byte) (b & 0x80) == 0) return 1;
        if ((byte) (b & 0xe0) == (byte) 0xc0) return 2;
        if ((byte) (b & 0xf0) == (byte) 0xe0) return 3;
        return 1;
    }

    public static int reverse(int value, int length) {
        byte[] bytes = parseInt(value, 4);
        swap(bytes);
        return toInt(bytes, 0, 4);
    }

    public static void main(String[] args) {
        System.out.println(reverse(524, 4));
        //55aa00490000001500000007b296ab5e7fc44352a06f8441d10ae639b296ab5e7fc44352a06f8441d10ae6390000020c0000004907000000010000006162766364
        byte[] bytes = "abvcd".getBytes();
        System.out.println(toHexString(bytes));
        System.out.println(Arrays.toString(bytes));
    }
}
